//  指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定具体类型的一种特性。

// 下面创建一个函数, 实现功能: 根据指定的数量 count和数据 value , 创建一个包含 count 个 value的数组
// 泛型函数
// function getArr(count:number,value:any):any[] {
//     let res:any[] = []
//     for (let i = 0; i < count; i++) {
//       res.push(value)
//     }
//     return res
// }

// console.log(getArr(10,"abc"));
// 泛型 怎么写  T U  K V  <>   写的位置
function getArr<T>(count:number,value:T):T[] {
    let res:T[] = []
    for (let i = 0; i < count; i++) {
      res.push(value)
    }
    return res
}

console.log(getArr<string>(10,"abc"));
console.log(getArr<number>(10,100));
console.log(getArr<boolean>(10,true));
console.log(getArr<object>(10,{name:"king"}));


/*
    2.使用泛型定义多个参数函数
*/

// function swap(num1:any,num2:any): any[] {
//     return [num2,num1]
// }

// console.log(swap("ab",100));


function swap<T,U>(num1:T,num2:U): [U,T] {
    return [num2,num1]
}

console.log(swap<string,number>("ab",100));
console.log(swap<undefined,Symbol>(undefined,Symbol("abc")));


/*
    3.定义泛型接口
    在定义接口时, 为接口中的属性或方法定义泛型类型
    在使用接口时, 再指定具体的泛型类型
*/

// interface  infoType {
//     name: string
//     list: number[]
// }

//泛型接口

interface  infoType<K,V> {
    name: K
    list: V[]
}

let obj: infoType<string,number> = {
    name:"king",
    list: [1,2,3,4,5]
}


/*
    4.泛型约束
    如果我们直接对一个泛型参数取 `length` 属性, 会报错, 因为这个泛型根本就不知道它有这个属性
*/

// 封装一个获取数组的长度的函数

interface lengthType{
    length:number
}


function getArrLength<T extends lengthType>(arr:T) {
    return  arr.length
}

// console.log(getArrLength<number>([1,2,3,4,5]) );
// console.log(getArrLength<string>(["a","b","c","d"]));


console.log(getArrLength([1,2,3,4,5]) );
console.log(getArrLength(["a","b","c","d"]));



/*
    5.定义泛型类 
        在定义类时, 为类中的属性或方法定义泛型类型
        在创建类的实例时, 再指定特定的泛型类型
    模拟队列 先进先出
*/

// generic  泛型 
class GenericNumber<T> {
    zeroValue: T 
    add: (x:T,y:T) =>  T
}

let gn = new GenericNumber<number>()
gn.zeroValue = 0;
gn.add = function (x,y) {
    return  x+y
}

console.log(gn.zeroValue);
console.log(gn.add(gn.zeroValue,10));

let gn1 = new GenericNumber<string>()
gn1.zeroValue = "hello";
gn1.add = function (x,y) {
    return  x+y
}

console.log(gn1.zeroValue);
console.log(gn1.add(gn1.zeroValue,"world"));


// 定义泛型类-模拟队列 先进先出 

class Queue<T> {
    list: T[] = []
    // 数组尾部添加
    addItem(value:T){
        this.list.push(value)
    }
    // 数组头部删除
    removeItem(){
        this.list.shift()
    }
}


let q = new Queue<number>()
q.addItem(1)
q.addItem(2)
q.addItem(3)
q.addItem(4)
console.log(q.list);
q.removeItem()
console.log(q.list);
q.removeItem()
console.log(q.list);
q.removeItem()
console.log(q.list);

let q2 = new Queue<string>()
q2.addItem("1")
q2.addItem("2")
q2.addItem("3")
q2.addItem("4")
console.log(q2.list);
q2.removeItem()
console.log(q2.list);
q2.removeItem()
console.log(q2.list);
q2.removeItem()
console.log(q2.list);


